package org.dicr.traffic.source;

import java.io.*;
import java.text.*;
import java.util.*;

import org.dicr.util.net.*;

/**
 * Traffic Element
 * 
 * @author <A href='http://dicr.org'>Igor A Tarasov</A>
 * @version 060629
 */
public class TrafficElement implements Serializable, Cloneable {
	private static final long serialVersionUID = 1L;

	/** Time of traffic element */
	private long time = System.currentTimeMillis();

	/** Router of traffic */
	private IP router = null;

	/** Source address */
	private IP src = null;

	/** Destination address */
	private IP dst = null;

	/** NextHop from router */
	private IP hop = null;

	/** Source address mask */
	private Mask srcMask = null;

	/** Destination address mask */
	private Mask dstMask = null;

	/** Source interface of router */
	private Integer srcIf = null;

	/** Destination intergace of router */
	private Integer dstIf = null;

	/** Source AS */
	private Integer srcAs = null;

	/** Destination AS */
	private Integer dstAs = null;

	/** Source port */
	private Integer srcPort = null;

	/** Destination port */
	private Integer dstPort = null;

	/** Protocol */
	private Integer proto = null;

	/** TCP tcpFlags */
	private Byte tcpFlags = null;

	/** TOS tcpFlags */
	private Byte tos = null;

	/** Packets count */
	private Long packets = null;

	/** Bytes count */
	private long bytes = 0;

	/**
	 * Constructor;
	 */
	public TrafficElement() {
		super();
	}

	/**
	 * Return bytes count
	 * 
	 * @return bytes count
	 */
	public long getBytes() {
		return this.bytes;
	}

	/**
	 * Set bytes count
	 * 
	 * @param count bytes count
	 */
	public void setBytes(final long count) {
		if (count < 0) throw new IllegalArgumentException("count: " + count);
		this.bytes = count;
	}

	/**
	 * Return destination address
	 * 
	 * @return destination address or null
	 */
	public IP getDst() {
		return this.dst;
	}

	/**
	 * Set destination address
	 * 
	 * @param ip destination address or null
	 */
	public void setDst(final IP ip) {
		this.dst = ip;
	}

	/**
	 * Return destination address AS
	 * 
	 * @return destination AS or null
	 */
	public Integer getDstAs() {
		return this.dstAs;
	}

	/**
	 * Set destination address AS
	 * 
	 * @param as destination AS or null
	 */
	public void setDstAs(final Integer as) {
		if (as != null && as.intValue() < 0) throw new IllegalArgumentException("AS: " + as);
		this.dstAs = as;
	}

	/**
	 * Return destination interface
	 * 
	 * @return destination interface number of router or null
	 */
	public Integer getDstIf() {
		return this.dstIf;
	}

	/**
	 * Set destination interface
	 * 
	 * @param number destination interface number of router or null
	 */
	public void setDstIf(final Integer number) {
		if (number != null && number.intValue() < 0) throw new IllegalArgumentException("number: " + number);
		this.dstIf = number;
	}

	/**
	 * Return destination port
	 * 
	 * @return destination port or null
	 */
	public Integer getDstPort() {
		return this.dstPort;
	}

	/**
	 * Set destination port
	 * 
	 * @param port destination port (0..65535) or null
	 */
	public void setDstPort(final Integer port) {
		if (port != null && (port.intValue() < 0 || port.intValue() > 65535)) throw new IllegalArgumentException(
		        "port: " + port);
		this.dstPort = port;
	}

	/**
	 * Return TCP tcpFlags
	 * 
	 * @return TCP-tcpFlags or null
	 */
	public Byte getTcpFlags() {
		return this.tcpFlags;
	}

	/**
	 * Set TCP tcpFlags
	 * 
	 * @param flags ORed TCP-tcpFlags or null
	 */
	public void setTcpFlags(final Byte flags) {
		this.tcpFlags = flags;
	}

	/**
	 * Return protocol
	 * 
	 * @return protocol number or null
	 */
	public Integer getProto() {
		return this.proto;
	}

	/**
	 * Set protocol
	 * 
	 * @param number protocol number or null
	 */
	public void setProto(final Integer number) {
		if (number != null && number.intValue() < 0) throw new IllegalArgumentException("number: " + number);
		this.proto = number;
	}

	/**
	 * Return router
	 * 
	 * @return router IP-address or null
	 */
	public IP getRouter() {
		return this.router;
	}

	/**
	 * Set router
	 * 
	 * @param ip router IP-address or null
	 */
	public void setRouter(final IP ip) {
		this.router = ip;
	}

	/**
	 * Return source
	 * 
	 * @return source address or null
	 */
	public IP getSrc() {
		return this.src;
	}

	/**
	 * Set source address
	 * 
	 * @param ip source IP-address or null
	 */
	public void setSrc(final IP ip) {
		this.src = ip;
	}

	/**
	 * Return source AS
	 * 
	 * @return AS number of source address or null
	 */
	public Integer getSrcAs() {
		return this.srcAs;
	}

	/**
	 * Set source AS
	 * 
	 * @param number AS number of source address or null
	 */
	public void setSrcAs(final Integer number) {
		if (number != null && number.intValue() < 0) throw new IllegalArgumentException("number: " + number);
		this.srcAs = number;
	}

	/**
	 * Return source interface
	 * 
	 * @return spurce interface number of router or null
	 */
	public Integer getSrcIf() {
		return this.srcIf;
	}

	/**
	 * Set source interface
	 * 
	 * @param number source interface number of router
	 */
	public void setSrcIf(final Integer number) {
		if (number != null && number.intValue() < 0) throw new IllegalArgumentException("number: " + number);
		this.srcIf = number;
	}

	/**
	 * Return source port
	 * 
	 * @return source port number or null
	 */
	public Integer getSrcPort() {
		return this.srcPort;
	}

	/**
	 * Set source port
	 * 
	 * @param port source port number or null
	 */
	public void setSrcPort(final Integer port) {
		if (port != null && (port.intValue() < 0 || port.intValue() > 65535)) throw new IllegalArgumentException(
		        "port: " + port);
		this.srcPort = port;
	}

	/**
	 * Return traffic time
	 * 
	 * @return time of traffic
	 */
	public long getTime() {
		return this.time;
	}

	/**
	 * Set traffic time
	 * 
	 * @param millis time of traffic
	 */
	public void setTime(final long millis) {
		if (millis < 0) throw new IllegalArgumentException("millis: " + millis);
		this.time = millis;
	}

	/**
	 * Return TOS (Type-Of-Service) flags
	 * 
	 * @return TOS flags or null
	 */
	public Byte getTos() {
		return this.tos;
	}

	/**
	 * Set TOS (Type-Of-Service) flags
	 * 
	 * @param flags TOS flags or null
	 */
	public void setTos(final Byte flags) {
		this.tos = flags;
	}

	/**
	 * Return NextHop
	 * 
	 * @return NextHop value of router or null
	 */
	public IP getHop() {
		return this.hop;
	}

	/**
	 * Set NextHop
	 * 
	 * @param ip address of next hop of router or null
	 */
	public void setHop(final IP ip) {
		this.hop = ip;
	}

	/**
	 * Return packets count
	 * 
	 * @return count of packets in this element or null
	 */
	public Long getPackets() {
		return this.packets;
	}

	/**
	 * Set packets count
	 * 
	 * @param count packets count for this element or null
	 */
	public void setPackets(final Long count) {
		if (count != null && count.intValue() < 0) throw new IllegalArgumentException("count: " + count);
		this.packets = count;
	}

	/**
	 * Return destination mask
	 * 
	 * @return mask of destination address or null
	 */
	public Mask getDstMask() {
		return this.dstMask;
	}

	/**
	 * Set destination mask
	 * 
	 * @param mask mask if destination address or null
	 */
	public void setDstMask(final Mask mask) {
		this.dstMask = mask;
	}

	/**
	 * Return source mask
	 * 
	 * @return mask of source address or null
	 */
	public Mask getSrcMask() {
		return this.srcMask;
	}

	/**
	 * Set source mask
	 * 
	 * @param mask mask of source address or null
	 */
	public void setSrcMask(final Mask mask) {
		this.srcMask = mask;
	}

	/**
	 * Clone traffic element.
	 * 
	 * @return copy of this traffic element
	 */
	@Override
	public TrafficElement clone() {
		final TrafficElement el = new TrafficElement();
		el.time = this.time;
		el.router = this.router;
		el.src = this.src;
		el.dst = this.dst;
		el.dstMask = this.dstMask;
		el.srcMask = this.srcMask;
		el.srcIf = this.srcIf;
		el.dstIf = this.dstIf;
		el.srcAs = this.srcAs;
		el.dstAs = this.dstAs;
		el.srcPort = this.srcPort;
		el.dstPort = this.dstPort;
		el.hop = this.hop;
		el.proto = this.proto;
		el.tcpFlags = this.tcpFlags;
		el.tos = this.tos;
		el.bytes = this.bytes;
		el.packets = this.packets;
		return el;
	}

	/**
	 * Convert to string
	 * 
	 * @return string
	 * @see java.lang.Object#toString()
	 */
	@Override
	public String toString() {
		final DateFormat df = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.MEDIUM);
		final StringBuilder sb = new StringBuilder("TrafficElement{");
		if (this.time > 0) sb.append("time=" + df.format(new Date(this.time)) + ",");
		if (this.router != null) sb.append("router=" + this.router + ",");
		if (this.src != null) sb.append("src=" + this.src + ",");
		if (this.dst != null) sb.append("dst=" + this.dst + ",");
		if (this.srcMask != null) sb.append("srcMask=" + this.srcMask + ",");
		if (this.dstMask != null) sb.append("dstMask=" + this.dstMask + ",");
		if (this.srcIf != null) sb.append("srcIf=" + this.srcIf + ",");
		if (this.dstIf != null) sb.append("dstIf=" + this.dstIf + ",");
		if (this.srcAs != null) sb.append("srcAs=" + this.srcAs + ",");
		if (this.dstAs != null) sb.append("dstAs=" + this.dstAs + ",");
		if (this.srcPort != null) sb.append("srcPort=" + this.srcPort + ",");
		if (this.dstPort != null) sb.append("dstPort=" + this.dstPort + ",");
		if (this.hop != null) sb.append("nextHop=" + this.hop + ",");
		if (this.proto != null) sb.append("proto=" + this.proto + ",");
		if (this.tcpFlags != null) sb.append("tcpFlags=" + this.tcpFlags + ",");
		if (this.tos != null) sb.append("tos=" + this.tos + ",");
		if (this.packets != null) sb.append("packets=" + this.packets + ",");
		sb.append("bytes=" + this.bytes);
		sb.append("}");
		return sb.toString();
	}

	/**
	 * @see java.lang.Object#hashCode()
	 */
	@Override
	public int hashCode() {
		final int PRIME = 31;
		int result = 1;
		result = PRIME * result + (this.dst == null ? 0 : this.dst.hashCode());
		result = PRIME * result + (this.dstAs == null ? 0 : this.dstAs.hashCode());
		result = PRIME * result + (this.dstIf == null ? 0 : this.dstIf.hashCode());
		result = PRIME * result + (this.dstMask == null ? 0 : this.dstMask.hashCode());
		result = PRIME * result + (this.dstPort == null ? 0 : this.dstPort.hashCode());
		result = PRIME * result + (this.hop == null ? 0 : this.hop.hashCode());
		result = PRIME * result + (this.proto == null ? 0 : this.proto.hashCode());
		result = PRIME * result + (this.router == null ? 0 : this.router.hashCode());
		result = PRIME * result + (this.src == null ? 0 : this.src.hashCode());
		result = PRIME * result + (this.srcAs == null ? 0 : this.srcAs.hashCode());
		result = PRIME * result + (this.srcIf == null ? 0 : this.srcIf.hashCode());
		result = PRIME * result + (this.srcMask == null ? 0 : this.srcMask.hashCode());
		result = PRIME * result + (this.srcPort == null ? 0 : this.srcPort.hashCode());
		result = PRIME * result + (this.tcpFlags == null ? 0 : this.tcpFlags.hashCode());
		result = PRIME * result + (this.tos == null ? 0 : this.tos.hashCode());
		return result;
	}

	/**
	 * @see java.lang.Object#equals(java.lang.Object)
	 */
	@Override
	public boolean equals(final Object obj) {
		if (this == obj) return true;
		if (obj == null) return false;
		if (this.getClass() != obj.getClass()) return false;
		final TrafficElement other = (TrafficElement) obj;
		if (this.dst == null) {
			if (other.dst != null) return false;
		} else if (!this.dst.equals(other.dst)) return false;
		if (this.dstAs == null) {
			if (other.dstAs != null) return false;
		} else if (!this.dstAs.equals(other.dstAs)) return false;
		if (this.dstIf == null) {
			if (other.dstIf != null) return false;
		} else if (!this.dstIf.equals(other.dstIf)) return false;
		if (this.dstMask == null) {
			if (other.dstMask != null) return false;
		} else if (!this.dstMask.equals(other.dstMask)) return false;
		if (this.dstPort == null) {
			if (other.dstPort != null) return false;
		} else if (!this.dstPort.equals(other.dstPort)) return false;
		if (this.hop == null) {
			if (other.hop != null) return false;
		} else if (!this.hop.equals(other.hop)) return false;
		if (this.proto == null) {
			if (other.proto != null) return false;
		} else if (!this.proto.equals(other.proto)) return false;
		if (this.router == null) {
			if (other.router != null) return false;
		} else if (!this.router.equals(other.router)) return false;
		if (this.src == null) {
			if (other.src != null) return false;
		} else if (!this.src.equals(other.src)) return false;
		if (this.srcAs == null) {
			if (other.srcAs != null) return false;
		} else if (!this.srcAs.equals(other.srcAs)) return false;
		if (this.srcIf == null) {
			if (other.srcIf != null) return false;
		} else if (!this.srcIf.equals(other.srcIf)) return false;
		if (this.srcMask == null) {
			if (other.srcMask != null) return false;
		} else if (!this.srcMask.equals(other.srcMask)) return false;
		if (this.srcPort == null) {
			if (other.srcPort != null) return false;
		} else if (!this.srcPort.equals(other.srcPort)) return false;
		if (this.tcpFlags == null) {
			if (other.tcpFlags != null) return false;
		} else if (!this.tcpFlags.equals(other.tcpFlags)) return false;
		if (this.tos == null) {
			if (other.tos != null) return false;
		} else if (!this.tos.equals(other.tos)) return false;
		return true;
	}
}
